# -*- coding: utf-8 -*-
import aiosqlite

from src       import utils
from src.types import Account

from fastapi           import Request, APIRouter, HTTPException
from fastapi.responses import Response, JSONResponse


accounts = APIRouter(prefix = "/accounts", dependencies = [utils.check.has_auth()])


@accounts.get("/search")
async def accounts_search(request: Request):
    sql = "SELECT id, firstName, lastName, email FROM users WHERE "

    params  = request.query_params
    filters = []

    for key in ("firstName", "lastName", "email"):
        if (value := params.get(key)) == None:
            continue
        
        if value.strip():
            filters.append(f'{key} LIKE "%{value}%"')

    try:
        skip  = int(params.get("form", 0)) if params.get("form") else 0
        limit = int(params.get("size", 10)) if params.get("size") else 10
    except:
        skip  = 0
        limit = 10

    if skip < 0 or limit <= 0:
        raise HTTPException(400, detail = "Invalid \"form\" or/and \"size\" parameters")

    method = params.get("method", "AND ")

    sql += method.join(filters)
    sql += f' LIMIT {limit} OFFSET {skip}'

    database: aiosqlite.Connection = request.app.database

    cursor = await database.execute(sql)
    result = await cursor.fetchall()

    return JSONResponse([{
        "id": i[0], "firstName": i[1], "lastName": i[2], "email": i[3]
    } for i in result], status_code = 200)


@accounts.get("/{accountId}")
async def accounts_get(request: Request, accountId: int = None):
    if accountId == None or 0 >= accountId:
        raise HTTPException(400, detail = "Invalid ID")

    account = await Account.get_by(request.app.database, id = accountId)

    if not account:
        raise HTTPException(404, detail = "The account with this ID was not found")
    return JSONResponse(account("id", "firstName", "lastName", "email"), status_code = 200)


@accounts.put("/{accountId}")
async def account_change(request: Request, accountId: int = None):
    if accountId == None or 0 >= accountId:
        raise HTTPException(400, detail = "Invalid ID")

    if request.cookies.get("id") != str(accountId):
        raise HTTPException(403, detail = "You can't update someone else's account")

    data = await utils.parse.dictionary(request)

    if not data:
        raise HTTPException(400, detail = "Failed to get passed values, specify them in JSON format")

    account = await Account.get_by(request.app.database, id = accountId)

    if not account:
        raise HTTPException(404, detail = "The account with this ID was not found")

    for key in ("email", "firstName", "lastName", "password"):
        value = data.get(key)

        if not value or value.strip() == "":
            raise HTTPException(400, detail = f"Missing or invalid {key}")

    email = data.get("email")

    if not utils.check.is_email(email):
        raise HTTPException(400, detail = "Invalid email")

    elif email != account.email:
        exists = await account.exists(email = email)

        if exists:
            raise HTTPException(409, detail = "An account with this email already exists")

    if data.get("password") == "-":
        data.pop("password")

    await account.update(**data)
    return JSONResponse(account("id", "firstName", "lastName", "email"), status_code = 200)


@accounts.delete("/{accountId}")
async def account_delete(request: Request, accountId: int = None):
    if accountId == None or 0 >= accountId:
        raise HTTPException(400, detail = "Invalid ID")

    if request.cookies.get("id") != str(accountId):
        raise HTTPException(403, detail = "You can't delete someone else's account")

    account = await Account.get_by(request.app.database, id = accountId)
    await account.delete()

    response = Response(None)
    response.delete_cookie("id")

    return response
